package ua.epam.classloaderlab;

import static java.io.File.separator;
import static java.lang.Boolean.FALSE;
import static ua.epam.classloaderlab.Util.compile;
import static ua.epam.classloaderlab.Util.concatenate;
import static ua.epam.classloaderlab.Util.load;

import java.io.File;
import java.io.IOException;

public class DynamicClassLoader extends ClassLoader {

	private String userDir = System.getProperty("user.dir");
	private String buildDir = concatenate(userDir, separator, "bin", separator);
	private String sourcePath[] = {};

	public void setSourcePath(String... sourcePath) {
		this.sourcePath = sourcePath;
	}

	public DynamicClassLoader() {
		super();
	}

	public DynamicClassLoader(ClassLoader parent) {
		super(parent);
	}

	@Override
	public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
		synchronized (getClassLoadingLock(name)) {
			String fileStub = name.replace(".", separator);
			File javaFile = getJavaFile(fileStub);

			// if java file (uncompiled) is absent, then it's NOT our job to load a class
			if (FALSE == javaFile.exists())
				return super.loadClass(name, resolve);

			File classFile = new File(concatenate(buildDir, fileStub, ".class"));

			if (FALSE == classFile.exists() || javaFile.lastModified() > classFile.lastModified())
				compile(javaFile.getAbsolutePath(), new File(buildDir));

			byte[] classBytes = null;
			try {
				classBytes = load(classFile);
			} catch (IOException e) {
				throw new ClassNotFoundException("Exception during reading classfile. ", e);
			}

			Class<?> clazz = defineClass(name, classBytes, 0, classBytes.length);
			if (resolve)
				resolveClass(clazz);
			return clazz;
		}
	}
	
	private File getJavaFile(String fileStub){
		for (String path: sourcePath){
			File javaFile = new File(concatenate(path, separator, fileStub, ".java"));
			if (javaFile.exists())
				return javaFile;
		}
		return new File(concatenate(userDir, separator, "src", separator, fileStub, ".java"));
		
	}

}